package com.yuandian.management.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.*;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.management.mapper.ConfConfirmedUrlMapper;
import com.yuandian.management.service.*;
import com.yuandian.management.vo.ConfirmedResourceVo;
import com.yuandian.utils.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 已确认URL资源表-Service实现
 * @author zfsn
 * @date 2023-3-17
 */
@Service
public class ConfConfirmedUrlServiceImpl extends ServiceImpl<ConfConfirmedUrlMapper, ConfConfirmedUrl>
		implements ConfConfirmedUrlService {

	@Autowired
	private ConfConfirmedUrlMapper confConfirmedUrlMapper;


	@Lazy
	@Autowired
	private ConfComponentResourceService confComponentResourceService;

	@Autowired
	private ConfResourceService confResourceService;

	@Autowired
	private ConfStepService confStepService;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private ConfExclusiveIndicatorService confExclusiveIndicatorService;

	@Autowired
	private ConfSegmentResourceRelationService confSegmentResourceRelationService;

	/**
	 * 查询数据
	 *
	 *
	 * @param confConfirmedUrl
	 * @param confConfirmedUrl 筛选条件
	 * @return 通用返回对象
	 */
	@Override
	public Page<Map<String, Object>> getConfirmedList(ConfConfirmedUrl confConfirmedUrl) {
		return confConfirmedUrlMapper.getConfirmedList(new Page<>(confConfirmedUrl.getPageNum(), confConfirmedUrl.getPageSize()), confConfirmedUrl);
	}


	/**
	 * 确认服务资源
	 *
	 * @param resourceCodes 业务服务资源编码数组
	 * @param isConfirm     确认或者取消
	 * @return 通用返回对象
	 */
	@Override
	public R<String> confirmOrCancelResourceByStatus(List<String> resourceCodes, boolean isConfirm) {
		int status = !isConfirm ? 0 : 1;
		// 1、根据编码集合查询服务资源
		QueryWrapper<ConfResource> queryWrapper = new QueryWrapper<>();
		queryWrapper.in("resource_code", resourceCodes);
		List<ConfResource> confResources = confResourceService.list(queryWrapper);
		Stream<ConfResource> confResourceStream = confResources.stream().filter(s -> !s.getStatus().equals(status));
		List<String> filterCodes = confResourceStream.map(ConfResource::getResourceCode).collect(Collectors.toList());
		if (!filterCodes.isEmpty()) {
			List<ConfResource> resourceList = confResourceStream.collect(Collectors.toList());
			// 2、确认/取消服务资源
			UpdateWrapper<ConfResource> updateWrapper = new UpdateWrapper<>();
			updateWrapper.in("resource_code", filterCodes);
			updateWrapper.set("status", status);
			if (!confResourceService.update(updateWrapper)) {
				return R.failed();
			}

			UpdateWrapper<ConfStep> stepUpdateWrapper = new UpdateWrapper<>();
			stepUpdateWrapper.in("step_code", filterCodes);
			stepUpdateWrapper.set("is_confirm", status);
			confStepService.update(stepUpdateWrapper);

			// 6、如果父服务资源存在，将父服务资源的专属指标进行同步
			for (ConfResource confResource : resourceList) {
				String resourceKeyCoding = confResource.getParentResourceCode();
				// 6.1、判断父服务资源是否存在
				if (StrUtil.isEmpty(resourceKeyCoding)) {
					continue;
				}
				// 6.2、存在父服务资源，查询父服务资源的专属指标
				QueryWrapper<ConfExclusiveIndicator> indicatorQueryWrapper = new QueryWrapper<>();
				indicatorQueryWrapper.eq("resource_code", resourceCodes);
				List<ConfExclusiveIndicator> confExclusiveIndicators = confExclusiveIndicatorService.list(indicatorQueryWrapper);

				// 6.3、先删除父资源同步过来的专属指标
				if (!confExclusiveIndicators.isEmpty()) {
					indicatorQueryWrapper.in("ei_code", confExclusiveIndicators.stream().map(ConfExclusiveIndicator::getEiCode).collect(Collectors.toList()));
					confExclusiveIndicatorService.remove(indicatorQueryWrapper);
				}

				// 6.4、如果是确认服务资源
				if (isConfirm) {
					List<ConfExclusiveIndicator> confExclusiveIndicatorList = new ArrayList<>();
					for (ConfExclusiveIndicator confExclusiveIndicator : confExclusiveIndicators) {
						confExclusiveIndicator.setUpdateBy(SecurityUtils.getUser().getName());
						confExclusiveIndicator.setUpdateTime(LocalDateTime.now());
						confExclusiveIndicatorList.add(confExclusiveIndicator);
					}
					if (confExclusiveIndicatorList.isEmpty()) {
						confExclusiveIndicatorService.saveBatch(confExclusiveIndicatorList);
					}

				}
			}
			return R.ok();
		} else {
			return R.ok();
		}
	}

	/**
	 * 通过主键删除数据
	 *
	 * @param id 主键
	 * @return 通用返回对象
	 */
	@Override
	public R<String> deleteById(Integer id) {
		ConfComponentResource confComponentResource = confComponentResourceService.getById(id);
		if (confComponentResource == null) {
			// 已确认服务资源不存在
			return R.failed("已确认服务资源不存在");
		}
		// 2、查询对应系统、网端、已确认url一致的已确认服务资源
		ConfConfirmedUrl dbCrv = new ConfConfirmedUrl();
		dbCrv.setSystemId(confComponentResource.getSystemId());
		dbCrv.setSegmentId(confComponentResource.getSegmentId());
		dbCrv.setConfirmedUrl(confComponentResource.getIdentifyStr());
		List<ConfConfirmedUrl> deleteList = super.list(Wrappers.query(dbCrv));

		// 3、更新业务服务资源为未使用，供数据重组重新发现
		List<Long> ids = new ArrayList<>();
		for (ConfConfirmedUrl cr : deleteList) {
			ids.add(Long.valueOf(cr.getId()));
		}
		confConfirmedUrlMapper.updateBusinessResourceNoUsed(confComponentResource.getIdentifyStr());

		// 4、批量删除已确认服务资源
		if (!ids.isEmpty()) {

			if (!super.removeByIds(ids)) {
				// 删除已确认服务资源失败
				return R.failed( "删除已确认服务资源失败");
			}
		}
		// 5、删除这条IT端组件服务资源
		if (!confComponentResourceService.removeById(confComponentResource.getId())) {
			// 删除关联的IT路径组件服务资源失败，或不存在关联的IT路径组件服务资源
			return R.failed("删除关联的IT路径组件服务资源失败，或不存在关联的IT路径组件服务资源");
		}

		return R.ok();
	}

	/**
	 * 再次确认服务资源
	 *
	 * @param crv 参数
	 * @return Result
	 */
	@Override
	public R confirmResourceAgain(ConfirmedResourceVo crv) {
		// 1、校验是否选择了同一系统、同一网端
		String[] segmentIds = crv.getSegmentId().split(",");
		for (String segmentId : segmentIds) {
			ConfConfirmedUrl dbCrv = new ConfConfirmedUrl();
			dbCrv.setSystemId(crv.getSystemId());
			dbCrv.setSegmentId(Integer.valueOf(segmentId));
			dbCrv.setConfirmedUrl(crv.getConfirmedUrl());
			if (confConfirmedUrlMapper.listCount(dbCrv) > 0) {
				// 该服务资源已存在相同的系统和网端
				return R.failed(null, "该服务资源已存在相同的系统和网端");
			}
		}
		// 2、查询符合再次确认的已确认服务资源
		ConfConfirmedUrl dbCrv = new ConfConfirmedUrl();
		dbCrv.setConfirmedUrl(crv.getConfirmedUrl());
		List<ConfConfirmedUrl> crAgainList = confConfirmedUrlMapper.list(dbCrv);
		if (crAgainList.isEmpty()) {
			// 没有符合条件的已确认服务资源
			return R.failed(null, "没有符合条件的已确认服务资源");
		}

		// 3、写入IT端组件服务资源表中，返回组件服务资源id
		List<Map<String, Object>> idList = new ArrayList<>();
		for (String segmentId : segmentIds) {
			Map<String, Object> m = new HashMap<>();
			ConfSegmentResourceRelation csrVo = new ConfSegmentResourceRelation();
			csrVo.setSystemId(crv.getSystemId());
			csrVo.setSegmentId(Integer.valueOf(segmentId));
			csrVo.setResourceStr(crv.getConfirmedUrl());
			// 3.1、检查同系统、同网端有没有相同的服务资源，若不存在就写入
			Long id = 0L;

			//todo
			List<ConfSegmentResourceRelation> dbCsr = confSegmentResourceRelationService.listData(csrVo);
			if (!dbCsr.isEmpty()) {
				id = Long.valueOf(dbCsr.get(0).getId());
			} else {
				csrVo.setCreateBy(SecurityUtils.getUser().getName());
				id = confSegmentResourceRelationService.insertAndGetId(csrVo);
				//todo
				// 3.2、更新redis状态，用来通知数据重组(IT端组件服务资源)
//				redisUtil.setCacheObject(ItPathResourceEnum.IT_PATH_RESOURCE_COMPONENT_SERVER_RESOURCE.getKey(),
//						ItPathResourceEnum.StatusEnum.OPEN.getStatus());
			}
			m.put("componentServerResourceId", id);
			m.put("segmentId", segmentId);
			idList.add(m);
		}

		// 4、写入已确认服务资源表中
		// originalUrl去重
		List<String> distinctUrl = new ArrayList<>();
		// 用来批量新增已确认服务资源
		List<ConfConfirmedUrl> confirmedResourceList = new ArrayList<>();
		crAgainList.forEach((cr) -> {
			String originalUrl = cr.getOriUrl();
			if (distinctUrl.indexOf(originalUrl) < 0) {
				idList.forEach((idMap) -> {
					ConfConfirmedUrl confirmedResource = new ConfConfirmedUrl();
					confirmedResource.setResourceCode(cr.getResourceCode());
					confirmedResource.setPrefixUrl(cr.getPrefixUrl());
					confirmedResource.setOriUrl(originalUrl);
					// 用前端传递的(可能经过修改的)
					confirmedResource.setConfirmedUrl(crv.getConfirmedUrl());
					// 来源和之前一样
					confirmedResource.setStatus(cr.getStatus());
					// 前端传递的系统编码
					confirmedResource.setSystemId(crv.getSystemId());
					// 前端传递的网端编码
					confirmedResource.setSegmentId(Integer.valueOf(String.valueOf(idMap.get("segmentId"))));
					confirmedResource.setResourceComponentId(Integer.valueOf(String.valueOf(idMap.get("componentServerResourceId"))));
					confirmedResourceList.add(confirmedResource);
				});
				distinctUrl.add(originalUrl);
			}
		});
		int status = insertConfirmedResourceBatch(confirmedResourceList);
		if (status <= 0) {
			// 写入已确认服务资源表中失败
			return R.failed(null, "写入已确认服务资源表中失败");
		}
		return R.ok();
	}

	@Transactional(rollbackFor = Exception.class)
	public int insertConfirmedResourceBatch(List<ConfConfirmedUrl> crList) {
		int status = 0;
		int subListLength = 500;
		if (crList.size() > subListLength) {
			List<List<ConfConfirmedUrl>> lists = ListUtils.partList(crList, subListLength);
			for (List<ConfConfirmedUrl> list : lists) {
				status = super.saveBatch(list) ? 1: 0;
			}
		} else {
			return super.saveBatch(crList) ? 1: 0;
		}
		return status;
	}
}